import java.rmi.*;
import java.rmi.server.UnicastRemoteObject;
import java.util.HashMap;
import java.net.*;

public class Client extends UnicastRemoteObject implements Client_itf {
	
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	private final static String ipServ = "127.0.0.1";	//adresse ip du serveur de nom
	private final static String port = "1099";			//port d'écoute du serveur de nom
	private static Server_itf server;					//accés au serveur
	
	private static Client cl;								//Numéro du site client
	private static HashMap<Integer, SharedObject> locObj;	//référence sur les objets locaux
	
   
	public Client() throws RemoteException {
        super();
    }

    ///////////////////////////////////////////////////
    //         Interface to be used by applications
    ///////////////////////////////////////////////////

    // initialization of the client layer
    public static void init() {
    	
    	try {
    		Client.cl = new Client();    	
			server = (Server_itf)Naming.lookup("rmi://" + ipServ + ":" + port +"/Serveur");
			locObj = new HashMap<Integer, SharedObject>();
			
			if(server == null){
				System.out.println("Le serveur n'est pas disponible");
	    	}
			
		} catch (MalformedURLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (RemoteException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (NotBoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
    }
	
    // lookup in the name server
    public static SharedObject lookup(String name) {
    	
    	SharedObject so = null;
    	
		try {
			int id;
			id = server.lookup(name);
	    	
	    	if(id == -1){
	    	//l'objet partagé n'est pas référencé auprés du serveur
	    		so = null;
	    	}
	    	else
	    	{
	    	//l'objet partagé existe
	    		so = new SharedObject();
		    	so.setId(id);
		    	so.setLock(SharedObjectState.NL);
		    	
		    	locObj.put(id, so);
	    	}
	    	
		} catch (RemoteException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		return so;
    }		
	
    // binding in the name server
    public static void register(String name, SharedObject_itf so) {
    	
    	try {
			server.register(name, so.getId());
		} catch (RemoteException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
    }

    // creation of a shared object
    public static SharedObject create(Object o) {
    	
    	SharedObject so = new SharedObject();
    	
		try {
			int id;
			id = server.create(o);
		
    		so.setId(id);
    		so.setLock(SharedObjectState.NL);
    		locObj.put(id, so);
    		
		} catch (RemoteException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		return so;
    }
    
	
    /////////////////////////////////////////////////////////////
    //    Interface to be used by the consistency protocol
    ////////////////////////////////////////////////////////////

    // request a read lock from the server
    public static Object lock_read(int id) {
    	 
    	Object o = null;
    	
    	try {
			o = server.lock_read(id, cl);
		} catch (RemoteException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		return o;
    }

    // request a write lock from the server
    public static Object lock_write (int id) {
    	
    	Object o = null;
    	
    	try {
			o = server.lock_write(id, cl);
		} catch (RemoteException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		return o;
    }

    // receive a lock reduction request from the server
    public Object reduce_lock(int id) throws java.rmi.RemoteException {
    	
    	Object o = locObj.get(id).reduce_lock();
    	return o;
    }


    // receive a reader invalidation request from the server
    public void invalidate_reader(int id) throws java.rmi.RemoteException {
    	
    	locObj.get(id).invalidate_reader();
    }


    // receive a writer invalidation request from the server
    public Object invalidate_writer(int id) throws java.rmi.RemoteException {
    	
    	Object o = locObj.get(id).invalidate_writer();
    	return o;
    }
}
